import {
    Body,
    Controller,
    Get,
    HttpStatus,
    Inject,
    Post,
    Query,
    SerializeOptions,
    UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';

import { RequireLogin, UserInfo } from '@/custom.decorator';

import { LoginUserDto } from './dtos/login.dto';
import { PaginteReturnDto, QueryUserDto } from './dtos/queryUser.dto';

import { RegisterUserDto, UpdatePasswordDto } from './dtos/register.dto';
import { UpdateUserDto } from './dtos/updateUser.dto';
import { CaptchaCode } from './types';

import { UserService } from './user.service';
import { LoginUserVo } from './vo/login-user.vo';
import { ApiOkResponse, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { UserEntity } from './entities';

@ApiTags('用户管理模块')
@Controller('user')
export class UserController {
    constructor(protected service: UserService) {}

    @Inject(ConfigService)
    protected configService: ConfigService;

    @Inject(JwtService)
    protected jwtService: JwtService;

    // 初始化
    @Get('initData')
    async initData() {
        await this.service.initData();
        return 'done';
    }

    // 注册
    @ApiQuery({ type: RegisterUserDto })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '验证码已失效/验证码错误/用户已存在',
        type: String,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '成功',
        type: String,
    })
    @Post('register')
    async register(@Body() data: RegisterUserDto) {
        console.log(data);
        return this.service.register(data);
    }

    // 登录
    @ApiQuery({ type: LoginUserDto })
    @ApiResponse({
        status: HttpStatus.BAD_REQUEST,
        description: '用户不存在/密码错误',
        type: String,
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '用户信息和 token',
        type: LoginUserVo,
    })
    @Post('login')
    async userLogin(@Body() loginUser: LoginUserDto): Promise<LoginUserVo> {
        const vo = await this.service.login(loginUser, false);

        return this.service.jwtData(vo);
    }
    @Post('admin/login')
    async adminLogin(@Body() loginUser: LoginUserDto) {
        const vo = await this.service.login(loginUser, true);
        return this.service.jwtData(vo);
    }
    @Get('refresh')
    async refresh(@Query('refreshToken') refreshToken: string) {
        try {
            const data = this.jwtService.verify(refreshToken);
            const user = await this.service.findUserById(data.userId, false);
            const accessToken = this.jwtService.sign(
                {
                    userId: user.id,
                    username: user.username,
                    roles: user.roles,
                    permissions: user.permissions,
                },
                {
                    expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m',
                },
            );
            const refreshToken1 = this.jwtService.sign(
                {
                    userId: user.id,
                },
                {
                    expiresIn: this.configService.get('jwt_refresh_token_expires_time') || '7d',
                },
            );
            return {
                accessToken,
                refreshToken: refreshToken1,
            };
        } catch (e) {
            throw new UnauthorizedException('token已失效,请重新登录');
        }
    }

    @Get('admin/refresh')
    async adminRefresh(@Query('refreshToken') refreshToken: string) {
        try {
            const data = this.jwtService.verify(refreshToken);
            const user = await this.service.findUserById(data.userId, false);

            const accessToken = this.jwtService.sign(
                {
                    userId: user.id,
                    username: user.username,
                    roles: user.roles,
                    permissions: user.permissions,
                },
                {
                    expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m',
                },
            );
            const refrsh = this.jwtService.sign(
                {
                    userId: user.id,
                    username: user.username,
                    roles: user.roles,
                    permissions: user.permissions,
                },
                {
                    expiresIn: this.configService.get('jwt_refresh_token_expires_time') || '7d',
                },
            );
            return {
                accessToken,
                refreshToken: refrsh,
            };
        } catch (e) {
            throw new UnauthorizedException('token已过期,请重新登录');
        }
    }

    // 查询单个用户
    @Get('info')
    @RequireLogin()
    async info(@UserInfo('userId') userId: number) {
        return this.service.findUserDetailById(userId);
    }

    // 修改密码
    @SerializeOptions({ groups: ['user-updatePassword'] })
    @Post(['updatePassword', 'admin/updatePassword'])
    @RequireLogin()
    async updatePassword(
        @UserInfo('userId') userId: number,
        @Body() passwordDto: UpdatePasswordDto,
    ) {
        return this.service.updatePassword(userId, passwordDto);
    }

    // 更新验证码
    @Get('updatePassword/captcha')
    @RequireLogin()
    async updatePasswordCaptcha(@Query('address') address: string) {
        const code = Math.random().toString().slice(2, 8);
        const codeData: CaptchaCode = {
            code,
            prefix: 'update_password_captcha_',
            address: `${address}`,
            subject: '更新密码验证码',
            html: `<p>您的更改密码验证码是${code}</p>`,
        };
        const res = await this.service.sendCode(codeData);
        return res;
    }

    // 获取验证码
    @ApiQuery({
        name: 'address',
        type: String,
        description: '邮箱地址',
        required: true,
        example: 'xxxx@xx.com',
    })
    @ApiResponse({
        status: HttpStatus.OK,
        description: '成功',
        type: String,
    })
    @Get('registerCaptcha')
    async captcha(@Query('address') address: string) {
        const code = Math.random().toString().slice(2, 8);
        const codeData: CaptchaCode = {
            code,
            prefix: 'captcha_',
            address: `${address}`,
            subject: '注册验证码',
            html: `<p>你的注册验证码是${code}</p>`,
        };
        const res = await this.service.sendCode(codeData);
        return res;
    }

    // 更新用户信息
    @Post(['update', 'admin/update'])
    @RequireLogin()
    async update(@UserInfo('userId') userId: number, @Body() updateUserDto: UpdateUserDto) {
        return this.service.update(userId, updateUserDto);
    }

    // 冻结用户
    @Get('freeze')
    @RequireLogin()
    async freeze(@Query('id') userId: number) {
        await this.service.freezeUserById(userId);
        return 'success';
    }

    @Get('list')
    @RequireLogin()
    async list(@Query() options: QueryUserDto): Promise<PaginteReturnDto> {
        return await this.service.findUsersByPage(options);
    }
}
